ホームに戻る
出典 :
MVVM Toolkit の概要 - Community Toolkits for .NET | Microsoft Learn ObservableProperty 属性 - Community Toolkits for .NET | Microsoft Learn .NET用 MVVM Toolkit v8でMVVMコードを短く #C# - Qiita .NET standard2.x時代のMVVMライブラリ #C# - Qiita CommunityToolkit.Mvvm V8 入門 #C# - Qiita [C#]WPFでのMVVMについてサンプルアプリからまとめ C# CommunityToolkit.Mvvm の学習2 ObservableProperty - sh1’s diary
関連 :
MVVMパターン INotifyPropertyChanged コマンド(ICommand) ReactiveProperty [C#]属性(Attribute) [C#]partial
目次 :

MVVM Toolkitとは

NuGetで公開されているライブラリで、MVVMパターンの構築を支援する機能を備えており、 INotifyPropertyChangedICommandを簡単に実装できる。

MVVM Toolkitが提供する機能

提供されるクラス 名前空間 担当機能
ObservableObject CommunityToolkit.Mvvm.ComponentModel INotifyPropertyChangedを実装したオブジェクトの基底クラス
RelayCommand CommunityToolkit.Mvvm.Input ICommandの実装
WeakReferenceMessenger CommunityToolkit.Mvvm.Messeging Messenger (詳細割愛)
IoC CommunityToolkit.Mvvm.DependencyInjection DI 、IoC (詳細割愛)

主な仕組み

画像 ViewModelとして用いるクラスを ObservableObject の派生クラスとして定義し、 データバインディングのソースとして用いるプロパティ(変更通知プロパティ)を含める。 コマンドは ICommand として作成し、これをコマンドバインディングのソースとする。

準備

画像 CommunityToolkit.Mvvm がインストールされていない場合は、Nuget より取得する。

実装例(MVVM Toolkit Ver.7)

変更通知プロパティ

ViewModel : MainWindowVM.cs
using CommunityToolkit.Mvvm.ComponentModel; //< ObservableObject の名前解決 // ViewModel : ObservableObject を継承 public class MainWindowVM : ObservableObject { // Name のバッキングフィールド private string _name; // プロパティ(バインドソース) public string Name { get => _name; set => SetProperty(ref _name, value); } }
View(XAML) : MainWindow.xaml (抜粋)
<!-- TextBlock.Text を DataContext の Name プロパティにバインド --> <TextBlock Text="{Binding Name}" />
ViewModel として用いるクラスは、ObservableObjectを継承して作成する。 ObservableObjectINotifyPropertyChangedを実装している。 プロパティの値を変更(set)した際は View への通知を行うため、SetProperty()を呼び出している。 また、INofityPropertyChangedを実装していない Model クラスをラップしてPropertyChangedに反応させることも可能である。
Model : Person.cs
public class Person { public string Name { get; set; } public int Age { get; set; } }
ViewModel : MainWindowVM.cs
using CommunityToolkit.Mvvm.ComponentModel; public class MainWindowVM : ObservableObject { private Person _person; public int Age { get => _person.Age; set => SetProperty( _person.Age, value, _person, (p, newval) => p.Age = newval ); } public string Name { get => _person.Name; set => SetProperty( _person.Name, value, _person, (p, newval) => p.Name = newval ); } }
この場合のSetProperty()の引数は、元の値、新しい値、対象オブジェクト、値更新時のコールバック、である。 _person のプロパティ更新をコールバック内で行っている点に注意。

コマンド

ViewModel : MainWindowVM.cs
using CommunityToolkit.Mvvm.ComponentModel; //< ObservableObject の名前解決 using CommunityToolkit.Mvvm.Input; //< RelayCommand の名前解決 public class MainWindowVM : ObservableObject { // プロパティ(バインドソース) public ICommand ClickCommand { get; } // コンストラクタ public MainWindowVM() { ClickCommand = new RelayCommand(Click); } // コマンドとしてに実行したい処理 private void Click() { Name = ""; } }
コマンドはICommandとして作成する。 実際にコマンドとして実行したい処理は Click() であるため、ViewModel のコンストラクタ中でRelayCommand化してプロパティに関連づける。 RelayCommandのコンストラクタには複数のオーバーロードが存在し、CanExecuteCommandParameterを指定することも可能である。 (詳細はリファレンス参照。)

Ver.8での変更

MVVM Toolkit Ver.8では各種機能をカスタム属性として利用できるようになり、コードの記述を大幅に削減できるようになった。 Ver.7での記法も引き続き有効である。
Ver.7 Ver.8
ViewModel
クラス定義
画像 画像
  • ViewModel はObservableObjectを継承
  • ViewModel にINotifyPropertyChanged属性を付与
  • クラスをpartial修飾
    (コードジェネレータにより追加コードが自動生成される)
変更通知
プロパティ
画像 画像
  • バインドソースとバッキングフィールドを記述
  • バインドソースのset内でSetProperty()をコール
  • バッキングフィールドのみを記述
  • バッキングフィールドにObservableProperty属性を付与
  • バインドソース Name は自動的に生成される
コマンド 画像 画像
  • バインドソースとハンドラを記述
  • ハンドラのみを記述
  • ハンドラにRelayCommand属性を付与
  • バインドソース GreetCommand は自動的に生成される

注意点

変更通知プロパティ、コマンドともにバインドソースとなるプロパティはコードジェネレータにより自動的に生成される。 その際、変更通知プロパティはバッキングフィールドの先頭文字を大文字にしたもの (例 : name ⇒ Name) コマンドはハンドラメソッドの後に Command を付与したものとなる。 (例 : Greet ⇒ GreetCommand) 変更通知プロパティの変更直前、直後に処理を行いたい場合、部分メソッドOn####Changing()On####Changed()を定義しておくと、 それぞれ実行されるようになる。 ( #### はプロパティ名)
[ObservableProperty] private string name; partial void OnNameChanging(string name) =>Console.WriteLine($"Nameプロパティが {name} に変更されようとしてます"); partial void OnNameChanged(string name) =>Console.WriteLine($"Nameプロパティが {name} に変更されました");